﻿using RockBus.Logging.Interfaces;
using RockBus.ServiceModel;
using RockBus.Transport.Interfaces;
using System;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading.Tasks;
using System.Transactions;

namespace RockBus.Services
{
    public partial class CbrService :
        IOneWay,
        IOneWayTxn
    {
        #region IOneWay

        IAsyncResult IOneWay.BeginProcessMessage(Message message, AsyncCallback callback, object state)
        {
            Logger.Log(MethodBase.GetCurrentMethod(), LogLevelEnum.Debug, Transaction.Current);

            return ReceivePort.ProcessMessage(message, null)
            .ToAsync(callback, state);
        }

        void IOneWay.EndProcessMessage(IAsyncResult asyncResult)
        {
            Logger.Log(MethodBase.GetCurrentMethod(), LogLevelEnum.Debug, Transaction.Current);

            Task task = asyncResult as Task;
            if ((null == task) || (null != task.Exception))
            {
                Exception exc = new Exception(string.Format("Delivery Failure on message with action {0}", OperationContext.Current.IncomingMessageHeaders.Action), (null == task) ? null : task.Exception);
                Logger.Log(MethodBase.GetCurrentMethod(), exc);
                throw exc;
            }
        }

        #endregion IOneWay

        #region IOneWayTxn

        [OperationBehavior(TransactionScopeRequired = true)]
        IAsyncResult IOneWayTxn.BeginProcessMessage(Message message, AsyncCallback callback, object state)
        {
            //Debug.Assert(null != Transaction.Current, "Ambient transaction should not be null.");

            Transaction transaction = Transaction.Current;
            if (transaction == null)
            {
                transaction = RoutingUtilities.TryGetTransaction(message);
            }

            Logger.Log(MethodBase.GetCurrentMethod(), LogLevelEnum.Debug, Transaction.Current);

            return ReceivePort.ProcessMessage(message, transaction)
            .ToAsync(callback, state);
        }

        void IOneWayTxn.EndProcessMessage(IAsyncResult asyncResult)
        {
            Logger.Log(MethodBase.GetCurrentMethod(), LogLevelEnum.Debug, Transaction.Current);

            Task task = asyncResult as Task;
            if ((null == task) || (null != task.Exception))
            {
                Transaction.Current.Rollback();

                Exception exc = new Exception(string.Format("Delivery Failure on message with action {0}", OperationContext.Current.IncomingMessageHeaders.Action), (null == task) ? null : task.Exception);
                Logger.Log(MethodBase.GetCurrentMethod(), exc);
                throw exc;
            }
        }

        #endregion IOneWayTxn
    }
}